﻿Imports SilverMemory.Engine

''' <summary>
''' silverlight UI game board.
''' </summary>
''' <remarks>calls may be from other threads, always use Control.Dispatcher</remarks>
Partial Public Class Board
  Inherits UserControl

  Private game As Engine.Game
  Private silverCardsList As New List(Of SilverCard)

  Public Sub New(ByVal game As Engine.Game)
    InitializeComponent()
    Me.game = game

    ButtonOK.Content = My.Resources.Texts.ButtonOK

    'be prepaaared
    AddHandler Me.game.GameStateChanged, AddressOf game_GamestateChanged
    AddHandler Me.SelectPlayersForm.PlayersReady, AddressOf Players_Ready

    Me.BlockingPanel.Visibility = Windows.Visibility.Visible
    Me.SelectPlayersForm.SetGame(game)
  End Sub

  ''' <summary>
  ''' react on some game state changes
  ''' </summary>
  Private Sub game_GamestateChanged(ByVal sender As Object, ByVal e As EventArgs)
    If TypeOf Me.game.GameState Is GameState.ReadyToStartGameState Then
      Me.Dispatcher.BeginInvoke(AddressOf preStartGame)
    ElseIf TypeOf Me.game.GameState Is GameState.FinishedGameState Then
      Me.Dispatcher.BeginInvoke(AddressOf gameFinished)
    End If
  End Sub

  ''' <summary>
  ''' make board ready to start the game
  ''' </summary>
  Private Sub preStartGame()
    addCardsToBoard()
    BlockingPanel.Visibility = Windows.Visibility.Visible

    'show selectplayersform to find out who is playing
    SelectPlayersForm.Visibility = Windows.Visibility.Visible
  End Sub

  ''' <summary>
  ''' make board show the finished message
  ''' </summary>
  Private Sub gameFinished()
    BlockingPanel.Visibility = Windows.Visibility.Visible
    BorderGameOver.Visibility = Windows.Visibility.Visible
    Dim winning = String.Empty
    Dim count = 0
    For Each player In Me.game.GameState.WinningPlayers
      winning &= player.Name & vbCrLf
      count += 1
    Next
    winning = winning.Trim().Replace(vbCrLf, ", ")
    If count = 1 Then
      winning = String.Format(My.Resources.Texts.GameOver, winning)
    Else
      winning = String.Format(My.Resources.Texts.GameOverMultiple, winning)
    End If

    TextBlockGameOver.Text = winning
  End Sub

  Private cardsPerRow As Integer
  ''' <summary>
  ''' UI is resized, reshuffle the cards.
  ''' </summary>
  Private Sub CardPanel_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles CardPanel.SizeChanged
    Dim dummyCard As New SilverCard()

    'calculate the total available width
    Me.cardsPerRow = CInt(e.NewSize.Width / dummyCard.Width)

    'add the cards
    addCardsToBoard()
  End Sub

  ''' <summary>
  ''' add the cards to the board in rows
  ''' </summary>
  Private Sub addCardsToBoard()

    'clear out current rows
    clearRows()

    'the index of the card in a row
    Dim index As Integer = 0

    'each row is a horizontal stackpanel
    Dim currentRow As StackPanel = Nothing
    Dim rowIndex = 0

    'distribute cards
    For Each card In game.GameState.CardsList
      If index = 0 Then
        'new row
        currentRow = findRow(rowIndex)
        rowIndex += 1
      End If

      'search the collection to find a silvercard to recycle
      Dim silverCard As SilverCard = Nothing
      For Each recyclableCard In Me.silverCardsList
        If recyclableCard.Card Is card Then
          silverCard = recyclableCard
          Exit For
        End If
      Next
      'make a new silvercard (UI element) if there was none to be recycled.
      If silverCard Is Nothing Then
        silverCard = New SilverCard(card)
        Me.silverCardsList.Add(silverCard) 'keep it for future recycling
        'add event handler for click
        AddHandler silverCard.Click, AddressOf CardClicked
      End If

      'add a the silvercard UI element to this row
      currentRow.Children.Add(silverCard)

      index += 1
      If index = Me.cardsPerRow Then
        index = 0 'initiate a new row
      End If
    Next

  End Sub

  ''' <summary>
  ''' find the row with the given index for recycling. It is created when none exists yet
  ''' </summary>
  ''' <param name="index">the row index</param>
  Private Function findRow(ByVal index As Integer) As StackPanel
    Dim foundIndex As Integer = 0
    'iterate through cardpanel children (=rows)
    For Each control In Me.CardPanel.Children
      If TypeOf control Is StackPanel Then
        'found a row
        If foundIndex = index Then
          Return CType(control, StackPanel)
        End If
        foundIndex += 1
      End If
    Next

    Dim newRow = New StackPanel() With {.Orientation = Orientation.Horizontal}
    CardPanel.Children.Add(newRow)
    Return newRow
  End Function

  Private Sub clearRows()
    'iterate through rows
    For Each control In Me.CardPanel.Children
      If TypeOf control Is StackPanel Then
        'found a row, clear the children of it
        CType(control, StackPanel).Children.Clear()
      End If
    Next
  End Sub

  ''' <summary>
  ''' event handler for click on a card
  ''' </summary>
  Private Sub CardClicked(ByVal sender As Object, ByVal e As EventArgs)
    Dim silverCard As SilverCard = CType(sender, SilverCard)

    'let game handle the click
    Me.game.CardSelected(silverCard.Card)
  End Sub

  ''' <summary>
  ''' players are ready, start the game.
  ''' </summary>
  Private Sub Players_Ready(ByVal sender As System.Object, ByVal e As EventArgs)
    Me.BlockingPanel.Visibility = Windows.Visibility.Collapsed
    Me.SelectPlayersForm.Visibility = Windows.Visibility.Collapsed

    For Each createdPlayer As Player In Me.SelectPlayersForm.GetPlayers()
      Dim silverPlayer As New SilverPlayerInfo(createdPlayer) With {.Margin = New Thickness(4)}

      Me.PlayerPanel.Children.Add(silverPlayer)
    Next

    Me.game.Start(Me.SelectPlayersForm)
  End Sub

  Private Sub LogButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles LogButton.Click
    LogText.Text = Logger.GetLog()
    If LogText.Visibility = Windows.Visibility.Visible Then
      LogText.Visibility = Windows.Visibility.Collapsed
    Else
      LogText.Visibility = Windows.Visibility.Visible
    End If

  End Sub

  Private Sub ButtonOK_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    BorderGameOver.Visibility = Windows.Visibility.Collapsed
  End Sub
End Class